<template>
  <div v-show="value" class="vue-image-crop-upload">
    <div class="vicp-wrap">
      <div class="vicp-close" @click="off">
        <i class="vicp-icon4"/>
      </div>

      <div v-show="step == 1" class="vicp-step1">
        <div class="vicp-drop-area" @dragleave="preventDefault" @dragover="preventDefault" @dragenter="preventDefault" @click="handleClick" @drop="handleChange">
          <i v-show="loading != 1" class="vicp-icon1">
            <i class="vicp-icon1-arrow"/>
            <i class="vicp-icon1-body"/>
            <i class="vicp-icon1-bottom"/>
          </i>
          <span v-show="loading !== 1" class="vicp-hint">{{ lang.hint }}</span>
          <span v-show="!isSupported" class="vicp-no-supported-hint">{{ lang.noSupported }}</span>
          <input v-show="false" v-if="step == 1" ref="fileinput" type="file" @change="handleChange">
        </div>
        <div v-show="hasError" class="vicp-error">
          <i class="vicp-icon2"/> {{ errorMsg }}
        </div>
        <div class="vicp-operate">
          <a @click="off" @mousedown="ripple">{{ lang.btn.off }}</a>
        </div>
      </div>

      <div v-if="step == 2" class="vicp-step2">
        <div class="vicp-crop">
          <div v-show="true" class="vicp-crop-left">
            <div class="vicp-img-container">
              <img
                ref="img"
                :src="sourceImgUrl"
                :style="sourceImgStyle"
                class="vicp-img"
                draggable="false"
                @drag="preventDefault"
                @dragstart="preventDefault"
                @dragend="preventDefault"
                @dragleave="preventDefault"
                @dragover="preventDefault"
                @dragenter="preventDefault"
                @drop="preventDefault"
                @touchstart="imgStartMove"
                @touchmove="imgMove"
                @touchend="createImg"
                @touchcancel="createImg"
                @mousedown="imgStartMove"
                @mousemove="imgMove"
                @mouseup="createImg"
                @mouseout="createImg">
              <div :style="sourceImgShadeStyle" class="vicp-img-shade vicp-img-shade-1"/>
              <div :style="sourceImgShadeStyle" class="vicp-img-shade vicp-img-shade-2"/>
            </div>

            <div class="vicp-range">
              <input :value="scale.range" type="range" step="1" min="0" max="100" @input="zoomChange">
              <i class="vicp-icon5" @mousedown="startZoomSub" @mouseout="endZoomSub" @mouseup="endZoomSub"/>
              <i class="vicp-icon6" @mousedown="startZoomAdd" @mouseout="endZoomAdd" @mouseup="endZoomAdd"/>
            </div>

            <div v-if="!noRotate" class="vicp-rotate">
              <i @mousedown="startRotateLeft" @mouseout="endRotate" @mouseup="endRotate">↺</i>
              <i @mousedown="startRotateRight" @mouseout="endRotate" @mouseup="endRotate">↻</i>
            </div>
          </div>
          <div v-show="true" class="vicp-crop-right">
            <div class="vicp-preview">
              <div v-if="!noSquare" class="vicp-preview-item">
                <img :src="createImgUrl" :style="previewStyle">
                <span>{{ lang.preview }}</span>
              </div>
              <div v-if="!noCircle" class="vicp-preview-item vicp-preview-item-circle">
                <img :src="createImgUrl" :style="previewStyle">
                <span>{{ lang.preview }}</span>
              </div>
            </div>
          </div>
        </div>
        <div class="vicp-operate">
          <a @click="setStep(1)" @mousedown="ripple">{{ lang.btn.back }}</a>
          <a class="vicp-operate-btn" @click="prepareUpload" @mousedown="ripple">{{ lang.btn.save }}</a>
        </div>
      </div>

      <div v-if="step == 3" class="vicp-step3">
        <div class="vicp-upload">
          <span v-show="loading === 1" class="vicp-loading">{{ lang.loading }}</span>
          <div class="vicp-progress-wrap">
            <span v-show="loading === 1" :style="progressStyle" class="vicp-progress"/>
          </div>
          <div v-show="hasError" class="vicp-error">
            <i class="vicp-icon2"/> {{ errorMsg }}
          </div>
          <div v-show="loading === 2" class="vicp-success">
            <i class="vicp-icon3"/> {{ lang.success }}
          </div>
        </div>
        <div class="vicp-operate">
          <a @click="setStep(2)" @mousedown="ripple">{{ lang.btn.back }}</a>
          <a @click="off" @mousedown="ripple">{{ lang.btn.close }}</a>
        </div>
      </div>
      <canvas v-show="false" ref="canvas" :width="width" :height="height"/>
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator';
import request from '@/utils/request';
import language from './utils/language';
import mimes from './utils/mimes';
import data2blob from './utils/data2blob';
import effectRipple from './utils/effectRipple';

const allowImgFormat: string[] = [
  'jpg',
  'png',
];

@Component
export default class ImageCropper extends Vue {
  // 域，上传文件name，触发事件会带上（如果一个页面多个图片上传控件，可以做区分
  @Prop({ default: 'avatar' })
  field!: string;
  // 原名key，类似于id，触发事件会带上（如果一个页面多个图片上传控件，可以做区分
  @Prop({ default: 0 })
  ki!: any;

  // 显示该控件与否
  @Prop({ default: true })
  value!: boolean;

  // 上传地址
  @Prop({ default: '' })
  url!: string;

  // 其他要上传文件附带的数据，对象格式
  @Prop({ default: null })
  params!: object;

  // Add custom headers
  @Prop({ default: null })
  headers!: object;

  // 剪裁图片的宽
  @Prop({ default: 200 })
  width!: number;

  // 剪裁图片的高
  @Prop({ default: 200 })
  height!: number;

  // 不显示旋转功能
  @Prop({ default: true })
  noRotate!: boolean;

  // 不预览圆形图片
  @Prop({ default: false })
  noCircle!: boolean;

  // 不预览方形图片
  @Prop({ default: false })
  noSquare!: boolean;

  // 单文件大小限制
  @Prop({ default: 10240 })
  maxSize!: number;

  // 语言类型
  @Prop({ default: 'zh' })
  langType!: string;

  // 语言包
  @Prop({ default: null })
  langExt!: object;

  // 图片上传格式
  @Prop({ default: 'png' })
  imgFormat!: string;

  // 是否支持跨域
  @Prop({ default: false })
  withCredentials!: boolean;

  // 图片的mime
  private mime = (): string => {
    return mimes[this.imageFormat] as string;
  };
  // 语言包
  private lang = (): object => {
    const lang = language[this.langType] ? language[this.langType] : language['en'];
    if (this.langExt) {
      Object.assign(lang, this.langExt);
    }
    return lang;
  };
  // 浏览器是否支持该控件
  private isSupported = () => {
    let isSupported = true;
    if (typeof FormData !== 'function') {
      isSupported = false;
    }
    return isSupported;
  };
  // 浏览器是否支持触屏事件
  private isSupportTouch = (): boolean => document.hasOwnProperty('ontouchstart');
  // 步骤, 1选择文件 2剪裁 3上传
  private step: number = 1;
  // 上传状态及进度, 0未开始 1正在 2成功 3错误
  private loading: number = 0;
  private progress: number = 0;
  // 是否有错误及错误信息
  private hasError: boolean = false;
  private errorMsg: string = '';
  // 需求图宽高比
  private ratio = (): number => this.width / this.height;
  // 原图地址、生成图片地址
  private sourceImg: HTMLImageElement|null = null;
  private sourceImgUrl = '';
  private createImgUrl = '';
  // 原图片拖动事件初始值
  private sourceImgMouseDown: { on: boolean, mX: number, mY: number, x: number, y: number } = {
    on: false,
    mX: 0, // 鼠标按下的坐标
    mY: 0,
    x: 0, // scale原图坐标
    y: 0,
  };
  // 生成图片预览的容器大小
  private previewContainer: { width: number, height: number } = {
    width: 100,
    height: 100,
  };
  // 原图容器宽高
  private sourceImgContainer: { width: number, height: number } = { // sic
    width: 240,
    height: 184, // 如果生成图比例与此一致会出现bug，先改成特殊的格式吧，哈哈哈
  };
  // 原图展示属性
  private scale: {
    zoomAddOn: boolean, // 按钮缩放事件开启
    zoomSubOn: boolean, // 按钮缩放事件开启
    range: number, // 最大100
    rotateLeft: boolean, // 按钮向左旋转事件开启
    rotateRight: boolean, // 按钮向右旋转事件开启
    degree: number, // 旋转度数
    x: number,
    y: number,
    width: number,
    height: number,
    maxWidth: number,
    maxHeight: number,
    minWidth: number, // 最宽
    minHeight: number,
    naturalWidth: number, // 原宽
    naturalHeight: number,
  } = {
    zoomAddOn: false, // 按钮缩放事件开启
    zoomSubOn: false, // 按钮缩放事件开启
    range: 1, // 最大100
    rotateLeft: false, // 按钮向左旋转事件开启
    rotateRight: false, // 按钮向右旋转事件开启
    degree: 0, // 旋转度数
    x: 0,
    y: 0,
    width: 0,
    height: 0,
    maxWidth: 0,
    maxHeight: 0,
    minWidth: 0, // 最宽
    minHeight: 0,
    naturalWidth: 0, // 原宽
    naturalHeight: 0,
  };

  get imageFormat(): string {
    return allowImgFormat.indexOf(this.imgFormat) === -1 ? 'jpg' : this.imgFormat;
  }

  // 进度条样式
  get progressStyle() {
    const {
      progress,
    } = this;
    return {
      width: progress + '%',
    };
  }

  // 原图样式
  get sourceImgStyle() {
    const {
      scale,
      sourceImgMasking,
    } = this;

    const top = scale.y + sourceImgMasking.y + 'px';
    const left = scale.x + sourceImgMasking.x + 'px';
    return {
      top,
      left,
      width: scale.width + 'px',
      height: scale.height + 'px',
      transform: 'rotate(' + scale.degree + 'deg)', // 旋转时 左侧原始图旋转样式
      '-ms-transform': 'rotate(' + scale.degree + 'deg)', // 兼容IE9
      '-moz-transform': 'rotate(' + scale.degree + 'deg)', // 兼容FireFox
      '-webkit-transform': 'rotate(' + scale.degree + 'deg)', // 兼容Safari 和 chrome
      '-o-transform': 'rotate(' + scale.degree + 'deg)', // 兼容 Opera
    };
  }

  // 原图蒙版属性
  get sourceImgMasking() {
    const ratio = this.ratio();
    const {
      width,
      height,
      sourceImgContainer,
    } = this;
    const sic = sourceImgContainer;
    const sicRatio = sic.width / sic.height; // 原图容器宽高比
    let x = 0;
    let y = 0;
    let w = sic.width;
    let h = sic.height;
    let scale = 1;
    if (ratio < sicRatio) {
      scale = sic.height / height;
      w = sic.height * ratio;
      x = (sic.width - w) / 2;
    }
    if (ratio > sicRatio) {
      scale = sic.width / width;
      h = sic.width / ratio;
      y = (sic.height - h) / 2;
    }
    return {
      scale, // 蒙版相对需求宽高的缩放
      x,
      y,
      width: w,
      height: h,
    };
  }

  // 原图遮罩样式
  get sourceImgShadeStyle() {
    const {
      sourceImgMasking,
      sourceImgContainer,
    } = this;
    const sic = sourceImgContainer;
    const sim = sourceImgMasking;
    const w = sim.width === sic.width ? sim.width : (sic.width - sim.width) / 2;
    const h = sim.height === sic.height ? sim.height : (sic.height - sim.height) / 2;
    return {
      width: w + 'px',
      height: h + 'px',
    };
  }

  get previewStyle() {
    const ratio = this.ratio();
    const {
      // width,
      // height,
      previewContainer,
    } = this;
    const pc = previewContainer;
    let w = pc.width;
    let h = pc.height;
    const pcRatio = w / h;
    if (ratio < pcRatio) {
      w = pc.height * ratio;
    }
    if (ratio > pcRatio) {
      h = pc.width / ratio;
    }
    return {
      width: w + 'px',
      height: h + 'px',
    };
  }

  @Watch('value')
  onValue(newValue: any) {
    if (newValue && this.loading !== 1) {
      this.reset();
    }
  }

  // 点击波纹效果
  ripple(e: MouseEvent) {
    effectRipple(e);
  }

  // 关闭控件
  off() {
    setTimeout(() => {
      this.$emit('input', false);
      this.$emit('close');
      if (this.step === 3 && this.loading === 2) {
        this.setStep(1);
      }
    }, 200);
  }

  // 设置步骤
  setStep(no: number) {
    // 延时是为了显示动画效果呢，哈哈哈
    setTimeout(() => {
      this.step = no;
    }, 200);
  }
  /* 图片选择区域函数绑定
   ---------------------------------------------------------------*/
  preventDefault(e: Event) {
    e.preventDefault();
    return false;
  }
  handleClick(e: Event) {
    if (this.loading !== 1) {
      if (e.target !== this.$refs.fileinput) {
        e.preventDefault();
        if ((document as any).activeElement !== this.$refs) {
          (this.$refs.fileinput as HTMLInputElement).click();
        }
      }
    }
  }
  handleChange(e: Event) {
    e.preventDefault();
    if (this.loading !== 1) {
      const files = (e.target as any).files || ((e as any).dataTransfer as any).files;
      this.reset();
      if (this.checkFile(files[0])) {
        this.setSourceImg(files[0]);
      }
    }
  }
  /* ---------------------------------------------------------------*/
  // 检测选择的文件是否合适
  checkFile(file: {type: string, size: number}) {
    const that = this;
    const  lang = this.lang() as any;
    const {
      maxSize,
    } = that;
    // 仅限图片
    if (file.type.indexOf('image') === -1) {
      that.hasError = true;
      that.errorMsg = lang.error.onlyImg;
      return false;
    }
    // 超出大小
    if (file.size / 1024 > maxSize) {
      that.hasError = true;
      that.errorMsg = lang.error.outOfSize + maxSize + 'kb';
      return false;
    }
    return true;
  }
  // 重置控件
  reset() {
    const that = this;
    that.loading = 0;
    that.hasError = false;
    that.errorMsg = '';
    that.progress = 0;
  }
  // 设置图片源
  setSourceImg(file: Blob) {
    const fr = new FileReader();
    fr.onload = (e: Event) => {
      this.sourceImgUrl = fr.result as string;
      this.startCrop();
    };
    fr.readAsDataURL(file);
  }
  // 剪裁前准备工作
  startCrop() {
    const that = this;
    const lang = this.lang() as any;
    const ratio= this.ratio();
    const {
      width,
      height,
      scale,
      sourceImgUrl,
      sourceImgMasking,
    } = that;
    const sim = sourceImgMasking;
    const img = new Image();
    img.src = sourceImgUrl;
    img.onload = function() {
      const nWidth = img.naturalWidth;
      const nHeight = img.naturalHeight;
      const nRatio = nWidth / nHeight;
      let w = sim.width;
      let h = sim.height;
      let x = 0;
      let y = 0;
      // 图片像素不达标
      if (nWidth < width || nHeight < height) {
        that.hasError = true;
        that.errorMsg = lang.error.lowestPx + width + '*' + height;
        return false;
      }
      if (ratio > nRatio) {
        h = w / nRatio;
        y = (sim.height - h) / 2;
      }
      if (ratio < nRatio) {
        w = h * nRatio;
        x = (sim.width - w) / 2;
      }
      scale.range = 0;
      scale.x = x;
      scale.y = y;
      scale.width = w;
      scale.height = h;
      scale.degree = 0;
      scale.minWidth = w;
      scale.minHeight = h;
      scale.maxWidth = nWidth * sim.scale;
      scale.maxHeight = nHeight * sim.scale;
      scale.naturalWidth = nWidth;
      scale.naturalHeight = nHeight;
      that.sourceImg = img;
      that.createImg();
      that.setStep(2);
    };
  }
  // 鼠标按下图片准备移动
  imgStartMove(e: MouseEvent) {
    e.preventDefault();
    // 支持触摸事件，则鼠标事件无效
    if (this.isSupportTouch && !(e as any).targetTouches) {
      return false;
    }
    const et = (e as any).targetTouches ? (e as any).targetTouches[0] : e;
    const {
      sourceImgMouseDown,
      scale,
    } = this;
    const simd = sourceImgMouseDown;
    simd.mX = et.screenX;
    simd.mY = et.screenY;
    simd.x = scale.x;
    simd.y = scale.y;
    simd.on = true;
  }
  // 鼠标按下状态下移动，图片移动
  imgMove(e: MouseEvent) {
    e.preventDefault();
    // 支持触摸事件，则鼠标事件无效
    if (this.isSupportTouch && !(e as any).targetTouches) {
      return false;
    }
    const et = (e as any).targetTouches ? (e as any).targetTouches[0] : e;
    const {
      sourceImgMouseDown: {
        on,
        mX,
        mY,
        x,
        y,
      },
      scale,
      sourceImgMasking,
    } = this;
    const sim = sourceImgMasking;
    const nX = et.screenX;
    const nY = et.screenY;
    const dX = nX - mX;
    const dY = nY - mY;
    let rX = x + dX;
    let rY = y + dY;
    if (!on) return;
    if (rX > 0) {
      rX = 0;
    }
    if (rY > 0) {
      rY = 0;
    }
    if (rX < sim.width - scale.width) {
      rX = sim.width - scale.width;
    }
    if (rY < sim.height - scale.height) {
      rY = sim.height - scale.height;
    }
    scale.x = rX;
    scale.y = rY;
  }
  // 按钮按下开始向右旋转
  startRotateRight(e: Event) {
    const that = this;
    const {
      scale,
    } = that;
    scale.rotateRight = true;
    function rotate() {
      if (scale.rotateRight) {
        const degree = ++scale.degree;
        that.createImg(degree);
        setTimeout(function() {
          rotate();
        }, 60);
      }
    }
    rotate();
  }

  // 按钮按下开始向右旋转
  startRotateLeft(e: Event) {
    const that = this;
    const {
      scale,
    } = that;
    scale.rotateLeft = true;
    function rotate() {
      if (scale.rotateLeft) {
        const degree = --scale.degree;
        that.createImg(degree);
        setTimeout(function() {
          rotate();
        }, 60);
      }
    }
    rotate();
  }
  // 停止旋转
  endRotate() {
    const {
      scale,
    } = this;
    scale.rotateLeft = false;
    scale.rotateRight = false;
  }
  // 按钮按下开始放大
  startZoomAdd(e: Event) {
    const that = this;
    const {
      scale,
    } = that;
    scale.zoomAddOn = true;
    function zoom() {
      if (scale.zoomAddOn) {
        const range = scale.range >= 100 ? 100 : ++scale.range;
        that.zoomImg(range);
        setTimeout(function() {
          zoom();
        }, 60);
      }
    }
    zoom();
  }
  // 按钮松开或移开取消放大
  endZoomAdd(e: Event) {
    this.scale.zoomAddOn = false;
  }
  // 按钮按下开始缩小
  startZoomSub(e: Event) {
    const that = this;
    const {
      scale,
    } = that;
    scale.zoomSubOn = true;
    function zoom() {
      if (scale.zoomSubOn) {
        const range = scale.range <= 0 ? 0 : --scale.range;
        that.zoomImg(range);
        setTimeout(function() {
          zoom();
        }, 60);
      }
    }
    zoom();
  }
  // 按钮松开或移开取消缩小
  endZoomSub(e: MouseEvent) {
    const {
      scale,
    } = this;
    scale.zoomSubOn = false;
  }
  zoomChange(e: MouseEvent) {
    if (e.target == null) {
      return;
    }
    this.zoomImg((e.target as any).value);
  }
  // 缩放原图
  zoomImg(newRange: any) {
    const that = this;
    const {
      sourceImgMasking,
      // sourceImgMouseDown,
      scale,
    } = this;
    const {
      maxWidth,
      maxHeight,
      minWidth,
      minHeight,
      width,
      height,
      x,
      y,
      // range,
    } = scale;
    const sim = sourceImgMasking;
    // 蒙版宽高
    const sWidth = sim.width;
    const sHeight = sim.height;
    // 新宽高
    const nWidth = minWidth + (maxWidth - minWidth) * newRange / 100;
    const nHeight = minHeight + (maxHeight - minHeight) * newRange / 100;
    // 新坐标（根据蒙版中心点缩放）
    let nX = sWidth / 2 - (nWidth / width) * (sWidth / 2 - x);
    let nY = sHeight / 2 - (nHeight / height) * (sHeight / 2 - y);
    // 判断新坐标是否超过蒙版限制
    if (nX > 0) {
      nX = 0;
    }
    if (nY > 0) {
      nY = 0;
    }
    if (nX < sWidth - nWidth) {
      nX = sWidth - nWidth;
    }
    if (nY < sHeight - nHeight) {
      nY = sHeight - nHeight;
    }
    // 赋值处理
    scale.x = nX;
    scale.y = nY;
    scale.width = nWidth;
    scale.height = nHeight;
    scale.range = newRange;
    setTimeout(function() {
      if (scale.range === newRange) {
        that.createImg();
      }
    }, 300);
  }
  // 生成需求图片
  createImg(e?: Event|number) {
    const that = this;
    const mime = this.mime();
    const {
      sourceImg,
      scale: {
        x,
        y,
        width,
        height,
        degree,
      },
      sourceImgMasking: {
        scale,
      },
    } = that;
    if (sourceImg == null) {
      return;
    }
    const canvas = that.$refs.canvas as HTMLCanvasElement;
    const ctx = canvas.getContext('2d');
    if (ctx == null) {
      return;
    }
    if (e) {
      // 取消鼠标按下移动状态
      that.sourceImgMouseDown.on = false;
    }
    canvas.width = that.width;
    canvas.height = that.height;
    ctx.clearRect(0, 0, that.width, that.height);
    // 将透明区域设置为白色底边
    ctx.fillStyle = '#fff';
    ctx.fillRect(0, 0, that.width, that.height);
    ctx.translate(that.width * 0.5, that.height * 0.5);
    ctx.rotate(Math.PI * degree / 180);
    ctx.translate(-that.width * 0.5, -that.height * 0.5);
    ctx.drawImage(sourceImg, x / scale, y / scale, width / scale, height / scale);
    that.createImgUrl = canvas.toDataURL(mime);
  }
  prepareUpload() {
    const {
      url,
      createImgUrl,
      field,
      ki,
    } = this;
    this.$emit('crop-success', createImgUrl, field, ki);
    if (typeof url === 'string' && url) {
      this.upload();
    } else {
      this.off();
    }
  }
  // 上传图片
  upload() {
    const that = this;
    const mime = this.mime();
    const lang = this.lang() as any;
    const {
      url,
      params,
      // headers,
      field,
      ki,
      createImgUrl,
      // withCredentials,
    } = this;
    const fmData = new FormData();
    fmData.append(field, data2blob(createImgUrl, mime), field + '.' + this.imageFormat);
    // 添加其他参数
    if (typeof params === 'object' && params) {
      Object.keys(params).forEach((k) => {
        fmData.append(k, (params as any)[k]);
      });
    }
    // 监听进度回调
    // const uploadProgress = function(event) {
    //   if (event.lengthComputable) {
    //     that.progress = 100 * Math.round(event.loaded) / event.total;
    //   }
    // };
    // 上传文件
    that.reset();
    that.loading = 1;
    that.setStep(3);
    request({
      url,
      method: 'post',
      data: fmData,
    }).then(resData => {
      that.loading = 2;
      that.$emit('crop-upload-success', resData.data);
    }).catch(err => {
      if (that.value) {
        that.loading = 3;
        that.hasError = true;
        that.errorMsg = lang.fail;
        that.$emit('crop-upload-fail', err, field, ki);
      }
    });
  }

  created() {
    // 绑定按键esc隐藏此插件事件
    document.addEventListener('keyup', (e) => {
      if (this.value && (e.key === 'Escape' || e.keyCode === 27)) {
        this.off();
      }
    });
  }
}
</script>

<!--
<style lang='sass' src="./scss/upload.scss">
</style> -->

<style>
@charset "UTF-8";
@-webkit-keyframes vicp_progress {
  0% {
    background-position-y: 0; }
  100% {
    background-position-y: 40px; } }
@keyframes vicp_progress {
  0% {
    background-position-y: 0; }
  100% {
    background-position-y: 40px; } }
@-webkit-keyframes vicp {
  0% {
    opacity: 0;
    -webkit-transform: scale(0) translatey(-60px);
            transform: scale(0) translatey(-60px); }
  100% {
    opacity: 1;
    -webkit-transform: scale(1) translatey(0);
            transform: scale(1) translatey(0); } }
@keyframes vicp {
  0% {
    opacity: 0;
    -webkit-transform: scale(0) translatey(-60px);
            transform: scale(0) translatey(-60px); }
  100% {
    opacity: 1;
    -webkit-transform: scale(1) translatey(0);
            transform: scale(1) translatey(0); } }
.vue-image-crop-upload {
  position: fixed;
  display: block;
  -webkit-box-sizing: border-box;
          box-sizing: border-box;
  z-index: 10000;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.65);
  -webkit-tap-highlight-color: transparent;
  -moz-tap-highlight-color: transparent; }
  .vue-image-crop-upload .vicp-wrap {
    -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
            box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
    position: fixed;
    display: block;
    -webkit-box-sizing: border-box;
            box-sizing: border-box;
    z-index: 10000;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    margin: auto;
    width: 600px;
    height: 330px;
    padding: 25px;
    background-color: #fff;
    border-radius: 2px;
    -webkit-animation: vicp 0.12s ease-in;
            animation: vicp 0.12s ease-in; }
    .vue-image-crop-upload .vicp-wrap .vicp-close {
      position: absolute;
      right: -30px;
      top: -30px; }
      .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4 {
        position: relative;
        display: block;
        width: 30px;
        height: 30px;
        cursor: pointer;
        -webkit-transition: -webkit-transform 0.18s;
        transition: -webkit-transform 0.18s;
        transition: transform 0.18s;
        transition: transform 0.18s, -webkit-transform 0.18s;
        -webkit-transform: rotate(0);
            -ms-transform: rotate(0);
                transform: rotate(0); }
        .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::after, .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::before {
          -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
                  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
          content: '';
          position: absolute;
          top: 12px;
          left: 4px;
          width: 20px;
          height: 3px;
          -webkit-transform: rotate(45deg);
              -ms-transform: rotate(45deg);
                  transform: rotate(45deg);
          background-color: #fff; }
        .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::after {
          -webkit-transform: rotate(-45deg);
              -ms-transform: rotate(-45deg);
                  transform: rotate(-45deg); }
        .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4:hover {
          -webkit-transform: rotate(90deg);
              -ms-transform: rotate(90deg);
                  transform: rotate(90deg); }
    .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area {
      position: relative;
      -webkit-box-sizing: border-box;
              box-sizing: border-box;
      padding: 35px;
      height: 170px;
      background-color: rgba(0, 0, 0, 0.03);
      text-align: center;
      border: 1px dashed rgba(0, 0, 0, 0.08);
      overflow: hidden; }
      .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 {
        display: block;
        margin: 0 auto 6px;
        width: 42px;
        height: 42px;
        overflow: hidden; }
        .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 .vicp-icon1-arrow {
          display: block;
          margin: 0 auto;
          width: 0;
          height: 0;
          border-bottom: 14.7px solid rgba(0, 0, 0, 0.3);
          border-left: 14.7px solid transparent;
          border-right: 14.7px solid transparent; }
        .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 .vicp-icon1-body {
          display: block;
          width: 12.6px;
          height: 14.7px;
          margin: 0 auto;
          background-color: rgba(0, 0, 0, 0.3); }
        .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 .vicp-icon1-bottom {
          -webkit-box-sizing: border-box;
                  box-sizing: border-box;
          display: block;
          height: 12.6px;
          border: 6px solid rgba(0, 0, 0, 0.3);
          border-top: none; }
      .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-hint {
        display: block;
        padding: 15px;
        font-size: 14px;
        color: #666;
        line-height: 30px; }
      .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-no-supported-hint {
        display: block;
        position: absolute;
        top: 0;
        left: 0;
        padding: 30px;
        width: 100%;
        height: 60px;
        line-height: 30px;
        background-color: #eee;
        text-align: center;
        color: #666;
        font-size: 14px; }
      .vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area:hover {
        cursor: pointer;
        border-color: rgba(0, 0, 0, 0.1);
        background-color: rgba(0, 0, 0, 0.05); }
    .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop {
      overflow: hidden; }
      .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left {
        float: left; }
        .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container {
          position: relative;
          display: block;
          width: 240px;
          height: 180px;
          background-color: #e5e5e0;
          overflow: hidden; }
          .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img {
            position: absolute;
            display: block;
            cursor: move;
            -webkit-user-select: none;
               -moz-user-select: none;
                -ms-user-select: none;
                    user-select: none; }
          .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img-shade {
            -webkit-box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
                    box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
            position: absolute;
            background-color: rgba(241, 242, 243, 0.8); }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img-shade.vicp-img-shade-1 {
              top: 0;
              left: 0; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img-shade.vicp-img-shade-2 {
              bottom: 0;
              right: 0; }
        .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-rotate {
          position: relative;
          width: 240px;
          height: 18px; }
          .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-rotate i {
            display: block;
            width: 18px;
            height: 18px;
            border-radius: 100%;
            line-height: 18px;
            text-align: center;
            font-size: 12px;
            font-weight: bold;
            background-color: rgba(0, 0, 0, 0.08);
            color: #fff;
            overflow: hidden; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-rotate i:hover {
              -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
                      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
              cursor: pointer;
              background-color: rgba(0, 0, 0, 0.14); }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-rotate i:first-child {
              float: left; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-rotate i:last-child {
              float: right; }
        .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range {
          position: relative;
          margin: 30px 0 10px 0;
          width: 240px;
          height: 18px; }
          .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5,
          .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6 {
            position: absolute;
            top: 0;
            width: 18px;
            height: 18px;
            border-radius: 100%;
            background-color: rgba(0, 0, 0, 0.08); }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5:hover,
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6:hover {
              -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
                      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
              cursor: pointer;
              background-color: rgba(0, 0, 0, 0.14); }
          .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5 {
            left: 0; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5::before {
              position: absolute;
              content: '';
              display: block;
              left: 3px;
              top: 8px;
              width: 12px;
              height: 2px;
              background-color: #fff; }
          .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6 {
            right: 0; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6::before {
              position: absolute;
              content: '';
              display: block;
              left: 3px;
              top: 8px;
              width: 12px;
              height: 2px;
              background-color: #fff; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6::after {
              position: absolute;
              content: '';
              display: block;
              top: 3px;
              left: 8px;
              width: 2px;
              height: 12px;
              background-color: #fff; }
          .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range] {
            display: block;
            padding-top: 5px;
            margin: 0 auto;
            width: 180px;
            height: 8px;
            vertical-align: top;
            background: transparent;
            -webkit-appearance: none;
               -moz-appearance: none;
                    appearance: none;
            cursor: pointer;
            /* 滑块
               ---------------------------------------------------------------*/
            /* 轨道
               ---------------------------------------------------------------*/ }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus {
              outline: none; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-webkit-slider-thumb {
              -webkit-box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
                      box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
              -webkit-appearance: none;
                      appearance: none;
              margin-top: -3px;
              width: 12px;
              height: 12px;
              background-color: #61c091;
              border-radius: 100%;
              border: none;
              -webkit-transition: 0.2s;
              transition: 0.2s; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-moz-range-thumb {
              box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
              -moz-appearance: none;
                   appearance: none;
              width: 12px;
              height: 12px;
              background-color: #61c091;
              border-radius: 100%;
              border: none;
              -webkit-transition: 0.2s;
              transition: 0.2s; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-thumb {
              box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
              appearance: none;
              width: 12px;
              height: 12px;
              background-color: #61c091;
              border: none;
              border-radius: 100%;
              -webkit-transition: 0.2s;
              transition: 0.2s; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:active::-moz-range-thumb {
              box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
              width: 14px;
              height: 14px; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:active::-ms-thumb {
              box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
              width: 14px;
              height: 14px; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:active::-webkit-slider-thumb {
              -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
                      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
              margin-top: -4px;
              width: 14px;
              height: 14px; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-webkit-slider-runnable-track {
              -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
                      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
              width: 100%;
              height: 6px;
              cursor: pointer;
              border-radius: 2px;
              border: none;
              background-color: rgba(68, 170, 119, 0.3); }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-moz-range-track {
              box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
              width: 100%;
              height: 6px;
              cursor: pointer;
              border-radius: 2px;
              border: none;
              background-color: rgba(68, 170, 119, 0.3); }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-track {
              box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
              width: 100%;
              cursor: pointer;
              background: transparent;
              border-color: transparent;
              color: transparent;
              height: 6px;
              border-radius: 2px;
              border: none; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-fill-lower {
              background-color: rgba(68, 170, 119, 0.3); }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-fill-upper {
              background-color: rgba(68, 170, 119, 0.15); }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-webkit-slider-runnable-track {
              background-color: rgba(68, 170, 119, 0.5); }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-moz-range-track {
              background-color: rgba(68, 170, 119, 0.5); }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-ms-fill-lower {
              background-color: rgba(68, 170, 119, 0.45); }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-ms-fill-upper {
              background-color: rgba(68, 170, 119, 0.25); }
      .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right {
        float: right; }
        .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview {
          height: 150px;
          overflow: hidden; }
          .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item {
            position: relative;
            padding: 5px;
            width: 100px;
            height: 100px;
            float: left;
            margin-right: 16px; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item span {
              position: absolute;
              bottom: -30px;
              width: 100%;
              font-size: 14px;
              color: #bbb;
              display: block;
              text-align: center; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item img {
              position: absolute;
              display: block;
              top: 0;
              bottom: 0;
              left: 0;
              right: 0;
              margin: auto;
              padding: 3px;
              background-color: #fff;
              border: 1px solid rgba(0, 0, 0, 0.15);
              overflow: hidden;
              -webkit-user-select: none;
                 -moz-user-select: none;
                  -ms-user-select: none;
                      user-select: none; }
            .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item.vicp-preview-item-circle {
              margin-right: 0; }
              .vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item.vicp-preview-item-circle img {
                border-radius: 100%; }
    .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload {
      position: relative;
      -webkit-box-sizing: border-box;
              box-sizing: border-box;
      padding: 35px;
      height: 170px;
      background-color: rgba(0, 0, 0, 0.03);
      text-align: center;
      border: 1px dashed #ddd; }
      .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-loading {
        display: block;
        padding: 15px;
        font-size: 16px;
        color: #999;
        line-height: 30px; }
      .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap {
        margin-top: 12px;
        background-color: rgba(0, 0, 0, 0.08);
        border-radius: 3px; }
        .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap .vicp-progress {
          position: relative;
          display: block;
          height: 5px;
          border-radius: 3px;
          background-color: #4a7;
          -webkit-box-shadow: 0 2px 6px 0 rgba(68, 170, 119, 0.3);
                  box-shadow: 0 2px 6px 0 rgba(68, 170, 119, 0.3);
          -webkit-transition: width 0.15s linear;
          transition: width 0.15s linear;
          background-image: -webkit-linear-gradient(135deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
          background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
          background-size: 40px 40px;
          -webkit-animation: vicp_progress 0.5s linear infinite;
                  animation: vicp_progress 0.5s linear infinite; }
          .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap .vicp-progress::after {
            content: '';
            position: absolute;
            display: block;
            top: -3px;
            right: -3px;
            width: 9px;
            height: 9px;
            border: 1px solid rgba(245, 246, 247, 0.7);
            -webkit-box-shadow: 0 1px 4px 0 rgba(68, 170, 119, 0.7);
                    box-shadow: 0 1px 4px 0 rgba(68, 170, 119, 0.7);
            border-radius: 100%;
            background-color: #4a7; }
      .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-error,
      .vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-success {
        height: 100px;
        line-height: 100px; }
    .vue-image-crop-upload .vicp-wrap .vicp-operate {
      position: absolute;
      right: 20px;
      bottom: 20px; }
      .vue-image-crop-upload .vicp-wrap .vicp-operate a {
        position: relative;
        float: left;
        display: block;
        margin-left: 10px;
        width: 100px;
        height: 36px;
        line-height: 36px;
        text-align: center;
        cursor: pointer;
        font-size: 14px;
        color: #4a7;
        border-radius: 2px;
        overflow: hidden;
        -webkit-user-select: none;
           -moz-user-select: none;
            -ms-user-select: none;
                user-select: none; }
        .vue-image-crop-upload .vicp-wrap .vicp-operate a:hover {
          background-color: rgba(0, 0, 0, 0.03); }
    .vue-image-crop-upload .vicp-wrap .vicp-error,
    .vue-image-crop-upload .vicp-wrap .vicp-success {
      display: block;
      font-size: 14px;
      line-height: 24px;
      height: 24px;
      color: #d10;
      text-align: center;
      vertical-align: top; }
    .vue-image-crop-upload .vicp-wrap .vicp-success {
      color: #4a7; }
    .vue-image-crop-upload .vicp-wrap .vicp-icon3 {
      position: relative;
      display: inline-block;
      width: 20px;
      height: 20px;
      top: 4px; }
      .vue-image-crop-upload .vicp-wrap .vicp-icon3::after {
        position: absolute;
        top: 3px;
        left: 6px;
        width: 6px;
        height: 10px;
        border-width: 0 2px 2px 0;
        border-color: #4a7;
        border-style: solid;
        -webkit-transform: rotate(45deg);
            -ms-transform: rotate(45deg);
                transform: rotate(45deg);
        content: ''; }
    .vue-image-crop-upload .vicp-wrap .vicp-icon2 {
      position: relative;
      display: inline-block;
      width: 20px;
      height: 20px;
      top: 4px; }
      .vue-image-crop-upload .vicp-wrap .vicp-icon2::after, .vue-image-crop-upload .vicp-wrap .vicp-icon2::before {
        content: '';
        position: absolute;
        top: 9px;
        left: 4px;
        width: 13px;
        height: 2px;
        background-color: #d10;
        -webkit-transform: rotate(45deg);
            -ms-transform: rotate(45deg);
                transform: rotate(45deg); }
      .vue-image-crop-upload .vicp-wrap .vicp-icon2::after {
        -webkit-transform: rotate(-45deg);
            -ms-transform: rotate(-45deg);
                transform: rotate(-45deg); }
.e-ripple {
  position: absolute;
  border-radius: 100%;
  background-color: rgba(0, 0, 0, 0.15);
  background-clip: padding-box;
  pointer-events: none;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
  -webkit-transform: scale(0);
      -ms-transform: scale(0);
          transform: scale(0);
  opacity: 1; }
  .e-ripple.z-active {
    opacity: 0;
    -webkit-transform: scale(2);
        -ms-transform: scale(2);
            transform: scale(2);
    -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
    transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
    transition: opacity 1.2s ease-out, transform 0.6s ease-out;
    transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out; }
</style>
